﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

using ComLib.Lang;
using ComLib.Lang.Plugins;

using FluentScript.IDE.Lib;
using FluentScript.IDE.Parts;


namespace FluentScript.IDE
{
    public class IdeController
    {
        private IIdeView _view;
        private Interpreter _i;
        private List<IViewPart> _parts;
        

        /// <summary>
        /// Initialize the view.
        /// </summary>
        /// <param name="view"></param>
        public IdeController(IIdeView view)
        {
            _view = view;
            _parts = new List<IViewPart>();
            _i = new Interpreter();
            _i.Context.Settings.MaxLoopLimit = 100;
            _i.Context.Settings.MaxFuncParams = 10;
            _i.Context.Settings.MaxCallStack = 10;
            _i.Context.Settings.MaxStringLength = 1000;
            _i.Context.Settings.MaxExceptions = 5;
            _i.Context.Plugins.RegisterAll();
            _i.Context.ExternalFunctions.Register("print", (exp) => Output.Print(exp));
        }


        /// <summary>
        /// Add a view part.
        /// </summary>
        /// <param name="part"></param>
        public void AddViewPart(IViewPart part)
        {
            _parts.Add(part);
        }


        /// <summary>
        /// Clears the results area.
        /// </summary>
        public void OnClear()
        {
            this.ForEach(part => part.Clear());
            _view.ClearErrors();
        }


        /// <summary>
        /// Run the code.
        /// </summary>
        public void OnRun()
        {
            _view.ClearErrors();

            string code = _view.SourceCode;
            code = code.Replace(";", "; ");
            
            try
            {
                OnClear();

                _i.Memory.Clear();

                // 2. Execute the code.
                _i.Execute(code);

                UpdateUI();
            }
            catch (Exception ex)
            {
                _view.SetError("Error occurred : " + Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace);
            }            
        }


        /// <summary>
        /// Updates the UI including all UI parts.
        /// </summary>
        public void UpdateUI()
        {
            this.ForEach(part => part.Update());            
        }


        private void ForEach(Action<IViewPart> callback)
        {
            foreach (var part in _parts)
            {
                part.Context.Ip = _i;
                callback(part);
            }
        }
    }
}
